/* "codecmux.c" */

/*********************/
/* CODEC-MULTIPLEXER */
/* for Secure Phone  */
/* (C) 2002 by NAH6  */
/*********************/

/*------------*/
/*  INCLUDES  */
/*------------*/

#include <stddef.h>
#include <stdlib.h>

#include "codecmux.h"

/*#include "celp_export.h"*/

/*--------------*/
/*  PROTOTYPES  */
/*--------------*/

static signed short codecmux__checkarg (unsigned char codec, \
                                        unsigned char revision);

/*----*/

static signed short codecmux__pcm16_encode (void *state,                  \
                                            const signed short *samples,  \
                                            unsigned char *encoded);
static signed short codecmux__pcm16_decode (void *state,                  \
                                            const unsigned char *encoded, \
                                            signed short *samples);

static signed short codecmux__pcm8_encode  (void *state,                  \
                                            const signed short *samples,  \
                                            unsigned char *encoded);
static signed short codecmux__pcm8_decode  (void *state,                  \
                                            const unsigned char *encoded, \
                                            signed short *samples);

static signed short codecmux__celp_open    (void *state);
static signed short codecmux__celp_encode  (void *state,                  \
                                            const signed short *samples,  \
                                            unsigned char *encoded);
static signed short codecmux__celp_decode  (void *state,                  \
                                            const unsigned char *encoded, \
                                            signed short *samples);

/*--------------*/
/*  KONSTANTEN  */
/*--------------*/

const unsigned char codecmux_maxrev[K_CODECMUX_CODECS] =
{
    0,  /* 0 = PCM16  */
    0,  /* 1 = PCM8   */
    0,  /* 2 = ADPCM4 */
    0,  /* 3 = GSMF */
    0,  /* 4 = GSMH */
    0,  /* 5 = GSME */
    0,  /* 6 = CELP */
    0   /* 7 = G721 */
};

/*----*/

const unsigned short codecmux_exblksize[K_CODECMUX_CODECS][K_CODECMUX_MAXREV] =
{
  {   1 },  /* 0 = PCM16  */
  {   1 },  /* 1 = PCM8   */
  {   2 },  /* 2 = ADPCM4 */
  { 160 },  /* 3 = GSMF   */
  { 160 },  /* 4 = GSMH   */
  { 160 },  /* 5 = GSME   */
  { 240 },  /* 6 = CELP   */
  { 160 }   /* 7 = G721   */
};


const unsigned short codecmux_coblksize[K_CODECMUX_CODECS][K_CODECMUX_MAXREV] =
{
  {   2 },  /* 0 = PCM16  */
  {   1 },  /* 1 = PCM8   */
  {   1 },  /* 2 = ADPCM4 */
  {  33 },  /* 3 = GSMF   */
  {  16 },  /* 4 = GSMH   */
  {  33 },  /* 5 = GSME   */
  {  18 },  /* 6 = CELP   */
  {  64 }   /* 7 = G721   */
};

/*====*/

static signed short (* const codecmuxtbl__open                \
                     [K_CODECMUX_CODECS][K_CODECMUX_MAXREV])  \
                    (void *state) =
{
  { NULL                 },  /* 0 = PCM16  */
  { NULL                 },  /* 1 = PCM8   */
  { NULL                 },  /* 2 = ADPCM4 */
  { NULL                 },  /* 3 = GSMF   */
  { NULL                 },  /* 4 = GSMH   */
  { NULL                 },  /* 5 = GSME   */
  { codecmux__celp_open  },  /* 6 = CELP   */
  { NULL                 }   /* 7 = G721   */
};


static signed short (* const codecmuxtbl__close               \
                     [K_CODECMUX_CODECS][K_CODECMUX_MAXREV])  \
                    (const void *state) =
{
  { NULL                  },  /* 0 = PCM16  */
  { NULL                  },  /* 1 = PCM8   */
  { NULL                  },  /* 2 = ADPCM4 */
  { NULL                  },  /* 3 = GSMF   */
  { NULL                  },  /* 4 = GSMH   */
  { NULL                  },  /* 5 = GSME   */
  { NULL                  },  /* 6 = CELP   */
  { NULL                  }   /* 7 = G721   */
};


static signed short (* const codecmuxtbl__encode              \
                     [K_CODECMUX_CODECS][K_CODECMUX_MAXREV])  \
                    (void *state,                             \
                     const signed short *samples,             \
                     unsigned char *encoded) =
{
  { codecmux__pcm16_encode },  /* 0 = PCM16  */
  { codecmux__pcm8_encode  },  /* 1 = PCM8   */
  { NULL                   },  /* 2 = ADPCM4 */
  { NULL                   },  /* 3 = GSMF   */
  { NULL                   },  /* 4 = GSMH   */
  { NULL                   },  /* 5 = GSME   */
  { codecmux__celp_encode  },  /* 6 = CELP   */
  { NULL                   }   /* 7 = G721   */
};


static signed short (* const codecmuxtbl__decode              \
                     [K_CODECMUX_CODECS][K_CODECMUX_MAXREV])  \
                    (void *state,                             \
                     const unsigned char *encoded,            \
                     signed short *samples) =
{
  { codecmux__pcm16_decode },  /* 0 = PCM16  */
  { codecmux__pcm8_decode  },  /* 1 = PCM8   */
  { NULL                   },  /* 2 = ADPCM4 */
  { NULL                   },  /* 3 = GSMF   */
  { NULL                   },  /* 4 = GSMH   */
  { NULL                   },  /* 5 = GSME   */
  { codecmux__celp_decode  },  /* 6 = CELP   */
  { NULL                   }   /* 7 = G721   */
};

/******************************************************************************/

/*-------------*/
/*  CODEC-MUX  */
/*-------------*/

signed short codecmux_open (unsigned char codec,    \
                            unsigned char revision, \
                            void *state)
{
  signed short n;

  n = codecmux__checkarg (codec, revision);
  if (n < 0)
    return n;

  if (codecmuxtbl__open[codec][revision] != NULL)
    n = (codecmuxtbl__open[codec][revision]) (state);
  else
    n = 0;

  return n;
}

/*----*/

signed short codecmux_close (unsigned char codec,    \
                             unsigned char revision, \
                             const void *state)
{
  signed short n;

  n = codecmux__checkarg (codec, revision);
  if (n < 0)
    return n;

  if (codecmuxtbl__close[codec][revision] != NULL)
    n = (codecmuxtbl__close[codec][revision]) (state);
  else
    n = 0;

  return n;
}

/*====*/

signed short codecmux_encode (unsigned char codec,         \
                              unsigned char revision,      \
                              void *state,                 \
                              const signed short *samples, \
                              unsigned char *encoded)
{
  signed short n;

  n = codecmux__checkarg (codec, revision);
  if (n < 0)
    return n;

  if (codecmuxtbl__encode[codec][revision] != NULL)
    n = (codecmuxtbl__encode[codec][revision]) (state, samples, encoded);
  else
    n = 0;

  return n;
}

/*----*/

signed short codecmux_decode (unsigned char codec,          \
                              unsigned char revision,       \
                              void *state,                  \
                              const unsigned char *encoded, \
                              signed short *samples)
{
  signed short n;

  n = codecmux__checkarg (codec, revision);
  if (n < 0)
    return n;

  if (codecmuxtbl__decode[codec][revision] != NULL)
    n = (codecmuxtbl__decode[codec][revision]) (state, encoded, samples);
  else
    n = 0;

  return n;
}

/*----------------------------------------------------------------------------*/

static signed short codecmux__checkarg (unsigned char codec, \
                                        unsigned char revision)
{
  if (codec >= K_CODECMUX_CODECS)
    return E_CODECMUX_CODEC;
  if (revision > codecmux_maxrev[codec])
    return E_CODECMUX_REVISION;
  return 0;
}

/*====*/

static signed short codecmux__pcm16_encode (void *state,                  \
                                            const signed short *samples,  \
                                            unsigned char *encoded)
{
  unsigned short x;

  x = *samples;
  *encoded++ = x & 0x00FF;
  *encoded   = x >> 8;

  return 0;
}

/*----*/

static signed short codecmux__pcm16_decode (void *state,                   \
                                            const unsigned char *encoded,  \
                                            signed short *samples)
{
  unsigned short x;
  unsigned char b;

  b = *encoded++;
  x = *encoded;
  x = (x << 8) | b;
  *samples = x;

  return 0;
}

/*====*/

static signed short codecmux__pcm8_encode (void *state,                  \
                                           const signed short *samples,  \
                                           unsigned char *encoded)
{
  signed short s;

  s = *samples;
  if (s < 0x7F80)
    s += 0x0080;
  s = s >> 8;
  *encoded = (unsigned char)s;

  return 0;
}

/*----*/

static signed short codecmux__pcm8_decode (void *state,                   \
                                           const unsigned char *encoded,  \
                                           signed short *samples)
{
  unsigned short x;

  x = *encoded;
  x = x << 8;
  *samples = x;

  return 0;
}

/*====*/

static signed short codecmux__celp_open (void *state)
{
  /* celp_init (); */
  return 0;
}

/*----*/

static signed short codecmux__celp_encode (void *state,                  \
                                           const signed short *samples,  \
                                           unsigned char *encoded)
{
  /* celp_encode (encoded, samples); */
  return 0;
}

/*----*/

static signed short codecmux__celp_decode (void *state,                   \
                                           const unsigned char *encoded,  \
                                           signed short *samples)
{
  /* celp_decode (samples, encoded); */
  return 0;
}


/*** EOF ***/
